package com.cetccloud.ap.proxy.processor.http;

import cn.hutool.core.map.MapUtil;
import com.alibaba.fastjson.JSON;
import com.cetccloud.ap.common.RuntimeCache;
import com.cetccloud.ap.common.SafeChecker;
import com.cetccloud.ap.proxy.common.ProxyContext;
import com.cetccloud.ap.proxy.processor.AbstractProcessor;
import com.cetccloud.ap.proxy.processor.exception.ProcessException;
import com.cetccloud.ap.proxy.processor.http.model.HttpCallParam;
import com.cetccloud.ap.proxy.processor.model.ProcessResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.client.ExchangeStrategies;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;

import java.time.Duration;
import java.util.Map;

/**
 * @ClassName HttpHandler
 * @Description TODO
 * @Author superz
 * @Date 2021/4/12 18:24
 * @Version 1.0
 **/
@Slf4j
@Component("httpCallProcessor")
public class HttpCallProcessor extends AbstractProcessor<HttpCallParam, ProcessResult> {

    @Autowired
    private SafeChecker safeChecker;

    @Autowired
    private RuntimeCache runtimeCache;

    @Override
    public Mono<ProcessResult> process(HttpCallParam httpCallParam, ProxyContext context) {
        try {
            // 安全校验
            if (!safeChecker.httpCanProxy(httpCallParam.getUrl())) {
                log.error("请求访问的url不在白名单中: " + httpCallParam.getUrl());
                return Mono.error(new ProcessException("请求访问的url不在白名单中: " + httpCallParam.getUrl()));
            }

            // 除了使用create快速生成 外还可以使用builder创建
            Mono<ProcessResult> mono = WebClient.builder()
                    .exchangeStrategies(ExchangeStrategies.builder()
                            .codecs(clientCodecConfigurer -> clientCodecConfigurer.
                                    defaultCodecs().maxInMemorySize(10*1024*1024))
                            .build())
                    .baseUrl(httpCallParam.getUrl()).build()
                    // 将info body 写入 proxy请求的body中
                    .method(HttpMethod.resolve(StringUtils.upperCase(httpCallParam.getMethod())))
                    .headers(httpHeaders -> {
                        Map<String, String> headers = httpCallParam.getHeaders();
                        if (MapUtil.isNotEmpty(headers)) {
                            headers.entrySet().stream().forEach(entry -> httpHeaders.set(entry.getKey(), entry.getValue()));
                        }
                        // 设置s10的token头
                        if (StringUtils.isNotBlank(runtimeCache.getS10Token())) {
                            headers.put("token", runtimeCache.getS10Token());
                        }
                    })
                    .contentType(MediaType.APPLICATION_JSON).bodyValue(httpCallParam.getBody())
                    .retrieve()
                    .bodyToMono(String.class).map(body -> ProcessResult.success().build(JSON.parse(body)))
                    .timeout(Duration.ofMillis(30_000));
            return mono;
        } catch (Exception e) {
            return Mono.error(new ProcessException(e));
        }
    }
}
